
package gui;

import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import javax.swing.JFrame;
import javax.swing.JOptionPane;

import urbanparks.JobSet;
import urbanparks.ParkSet;
import urbanparks.User;
import urbanparks.UserSet;
import exceptions.FileFormatException;

/**
 * The controller class for the Urban Parks program. This
 * class manages the GUI and has references to the model
 * classes utilized by the GUI.
 * 
 * @author Michelle Miller
 * @version Winter 2012
 */
@SuppressWarnings("serial")
public class UrbanParksManagerFrame extends JFrame {

  /**
   * A string constant that informs the user that there
   * was a file I/O error.
   */
  private static final String FILE_ERROR_MSG =
      "<html>A system file was not found.<br><center>" +
          "Please contact your system administrator." +
          "</center></html>";

  /**
   * A reference to the Log In Screen GUI Component.
   */
  private final LogInPanel my_login_panel;

  /**
   * A reference to the Main Page Screen GUI Component.
   */
  private MainPagePanel my_main_page_panel;

  /**
   * A reference to the object that contains all of the
   * user data and behavior.
   */
  private UserSet my_user_set;

  /**
   * A reference to the object that contains all of the job
   * data and behavior.
   */
  private JobSet my_job_set;

  /**
   * A reference to the object that contains all of the
   * park data and behavior.
   */
  private ParkSet my_park_set;

  /**
   * The user object that is currently signed into the
   * system.
   */
  private User my_current_user;

  /**
   * Constructor for the UrbanParksManagerFrame that
   * accepts four strings as parameters. The four strings
   * are the file path for the job file, the user file, the
   * park file, and the configuration file. These are the
   * files that store the persistent data in the system.
   * The constructor sets up the program for use by reading
   * in all of the information from the files and setting
   * up the GUI.
   * 
   * @param the_config_file A filepath for the file holding
   *          information about the configurations. The 
   *          configurations file should contain the
   *          following elements in this order as comma
   *          seperated values: the string filename for the
   *          park file, the string filename for the job
   *          file, the string filename for the user file,
   *          an integer representing the max number of
   *          jobs pending, and an integer representing the
   *          max number of jobs per week.
   */
  public UrbanParksManagerFrame(
      final String the_config_file) {
    super("Urban Parks");
    this.setDefaultCloseOperation(
        JFrame.DO_NOTHING_ON_CLOSE);

    this.addWindowListener( new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        UrbanParksManagerFrame frame =
            (UrbanParksManagerFrame) e.getSource();

        frame.getJobSet().writeFile();
        frame.getUserSet().writeFile();
        frame.getParkSet().writeFile();
        frame.dispose();
      }
    });
    final List<String> configs =
        parseFilenamesSettings(openFile(the_config_file));


    initializeSets(configs);

    my_login_panel = new LogInPanel(this);

  }

  /**
   * Initializes the JobSet, ParkSet and UserSet from the
   * filename and configurations found in the
   * configurations file.
   * 
   * @param the_configurations The list of configurations.
   */
  private void initializeSets(
      final List<String> the_configurations) {
    final int max_pending =
        getInt(the_configurations.get(3));
    final int max_weekly =
        getInt(the_configurations.get(4));
    try {
      my_park_set =
          new ParkSet(openFile(the_configurations.get(0)));
      my_job_set =
          new JobSet(openFile(the_configurations.get(1)),
          max_pending, max_weekly);
      my_user_set =
          new UserSet(openFile(the_configurations.get(2)));
    } catch (FileFormatException e) {
      JOptionPane.showMessageDialog(this, e.getMessage());
      this.dispose();
    }
  }

  /**
   * Private helper method to do error checking for parsing
   * a String to an int.
   * 
   * @param the_string The string to try to parse to an int
   * @return The integer represented by the_string
   */
  private int getInt(final String the_string) {
    int result = -1;
    try {
      result = Integer.parseInt(the_string);
    } catch (final NumberFormatException e) {
      JOptionPane.showMessageDialog(this, FILE_ERROR_MSG);
      this.dispose();
    }
    return result;
  }

  /**
   * Private helper method to parse the configuration file.
   * 
   * @param the_file The configuration file object.
   * @return A list of the values within the configuration
   *   files.
   */
  private List<String> parseFilenamesSettings(
      final File the_file) {
    final List<String> result = new ArrayList<String>();
    Scanner s = null;
    try {
      s = new Scanner(the_file);
    } catch (final FileNotFoundException e) {
      JOptionPane.showMessageDialog(this, FILE_ERROR_MSG);
      this.dispose();
    }
    String[] tokens;
    String line = "";
    while (s.hasNextLine()) {

      line = s.nextLine();
      if (line.length() > 0) {
        tokens = line.split(",");
        for (String t : tokens) {
          result.add(t);
        }
      }       
    }
    return result;
  }

  /**
   * Private helper method to create a file from a
   * filepath. The method displays an error message and
   * closes if the file was unable to be created for
   * whatever reason.
   * 
   * @param the_file The filepath to try to create a file
   *          from.
   * @return The file created from the filepath.
   */
  private File openFile(final String the_file) {
    File file = null;
    try {
      file = new File(the_file);
    } catch (final NullPointerException e) {
      JOptionPane.showMessageDialog(this, FILE_ERROR_MSG);
      this.dispose();
    }
    return file;

  }

  /**
   * Returns a reference to the current user logged in to
   * the system.
   * 
   * @return A reference to the current user logged in to
   *         the system.
   */
  public User getCurrentUser() {
    return my_current_user;
  }

  /**
   * Sets the current user logged in to the system to the
   * user parameter provided.
   * 
   * @param the_new_user The user to set as the current
   *          user.
   */
  public void setCurrentUser(final User the_new_user) {
    my_current_user = the_new_user;
  }

  /**
   * Returns a reference to the UserSet used by this
   * program.
   * 
   * @return A reference to the UserSet used by this
   *         program.
   */
  public UserSet getUserSet() {
    return my_user_set;
  }

  /**
   * Returns a reference to the JobSet used by this
   * program.
   * 
   * @return A reference to the JobSet used by this
   *  program.
   */
  public JobSet getJobSet() {
    return my_job_set;
  }

  /**
   * Returns a reference to the ParkSet used by this
   * program.
   * 
   * @return A reference to the ParkSet used by this
   *         program.
   */
  public ParkSet getParkSet() {
    return my_park_set;
  }

  /**
   * This method switched the view from the login page to
   * the Main page. This is called when a valid user logs
   * in.
   */
  public void switchToMainPage() {
    my_main_page_panel = new MainPagePanel(this);
    setContentPane(my_main_page_panel);
    this.setTitle("Main Page Screen"); 
    this.setExtendedState(Frame.MAXIMIZED_BOTH);
    this.setMinimumSize(this.getSize());
    this.pack();
    this.repaint();
  }

  /**
   * This method switched the view from the main page to
   * the login page. This is called when a user signs
   * out.
   */
  public void switchToLoginPage() {
    my_login_panel.reset();
    setContentPane(my_login_panel);
    this.setTitle("Log-In Screen");

    this.setMinimumSize(new Dimension(500, 200));
    this.repaint();
    this.setSize(new Dimension(500, 200));
  }

  /**
   * This method starts the program and sets the view to
   * the login page.
   */
  public void start() {
    switchToLoginPage();
    this.setVisible(true);
    this.pack();
  }

}
